using System;
using System.Drawing;
using UltimateDefend.Properties;
using System.Drawing.Imaging;
using System.Threading;

namespace UltimateDefend
{
    public abstract class ITower
    {
        #region Attributes
        protected Point m_pointPos;     // Vi tri dat tower, tinh tu trong tam cua hcn
        protected string m_sName;       // Ten tower
        protected int m_nDamage;        // Suc huy diet cua tower
        protected int m_nRange;         // Tam ban cua tower
        protected int m_nAtkSpeed;      // Toc do ban cua tower
        protected int m_nLevel;         // Level, co khi khong can
        protected int m_nCost;          // Gia tien de xay dung hoac upgrade
        protected int m_nRadixCost;     // He so tien khi ban tru

        protected Bitmap m_bmDisplay;   // Hinh anh hien thi cua tru
        protected int m_iHeight;
        protected int m_iWidth;
        protected ImageAttributes m_imgAtt;

        protected bool m_IsSelect;      //true: tower dang duoc chon, false: tower khong duoc chon
        protected IEnemy m_AttackEnemy; //luu quan linh dang bi tower tan cong      
        protected IEnemy[] m_GroupEnemy;  //luu het tat ca creep hien co trong level 
       
        protected IAnimation m_animation;   //luu animation cua tower

        /*******************************/
        //Luu y sau khi choi het vong phai destroy het tat ca tower
        protected bool m_IsDestroy;       //cho biet trang thai cua tower
        /*******************************/

        protected Thread m_thread;      //thread de chay tower
        protected ThreadStart m_ts;
        #endregion

        #region Properties
        public IEnemy AttackEnemy
        {
            get { return this.m_AttackEnemy; }
            set { this.m_AttackEnemy = value; }
        }
       
        public IEnemy[] GroupEnemy
        {
            set { this.m_GroupEnemy = value; }
            get { return this.m_GroupEnemy; }
        }

        public bool IsDestroy
        {
            get { return this.m_IsDestroy; }
            set { this.m_IsDestroy = value; }
        }

        public Point Position
        {
            get
            {
                return this.m_pointPos;
            }
            set
            {
                this.m_pointPos = value;
            }
        }

        public int Cost
        { get { return m_nCost; } }

        public int Height
        {
            get { return this.m_iHeight; }
        }

        public int Width
        {
            get { return this.m_iWidth; }
        }

        public bool IsSelect
        {
            get { return this.m_IsSelect; }
            set { this.m_IsSelect = value; }
        }
        public IAnimation Animation
        {
            get { return this.m_animation; }
        }
        #endregion

        #region Methods

        /// <summary>
        /// ham de bat dau xu ly tower
        /// </summary>
        /// <param name="currBmp">bmp hien tai</param>
        /// <param name="arrEnemy">danh sach cac enemy hien co</param>
        public void Start(ref IEnemy[] arrEnemy)
        {
            //khoi gan gia tri
            this.m_GroupEnemy = arrEnemy;
            
            this.m_ts = new ThreadStart(this.Gaurd);
            this.m_thread = new Thread(this.m_ts);
            this.m_thread.Start();
        }
        public void Gaurd()
        {
            //khoi tao cho tower

            //lap cho toi khi ket thuc vong choi
            while (!this.m_IsDestroy)
            {
                //neu tower chua tan cong creep nao het
                if (this.m_AttackEnemy == null)
                {
                    //tim creep vao range
                    int i;
                    for (i = 0; i < this.m_GroupEnemy.Length; i++)
                    {
                        //neu tan cong duoc
                        if (this.CanAttack(this.m_GroupEnemy[i]))
                        {
                            //luu lai con creep dang tan cong
                            this.m_AttackEnemy = this.m_GroupEnemy[i];
                            
                            break;
                        }
                    }
                }
                else
                {                    
                    //truong hop dang tan cong mot con creep
                    //trong khi con creep chua chet hoac chua ra khoi range
                    while (this.CanAttack(this.m_AttackEnemy))
                    {
                        //ban voi toc doc atkspeed
                            this.m_animation = new ShootOut(this.m_pointPos, this.m_AttackEnemy.Position, this.m_nAtkSpeed);

                        //tan cong con creep
                        this.Attack(ref this.m_AttackEnemy);
                        //Thread.Sleep(10);

                    }
                    this.m_AttackEnemy = null;
                    this.m_animation = null;                    
                }
                /*****************************/
                //thread phai sleep bang voi lai timer
                Thread.Sleep(10);
                /*****************************/
            }
            this.m_IsDestroy = true;
        }

        /// <summary>
        /// kiem tra xem co the tan cong duoc con creep hay khong
        /// </summary>
        /// <param name="enemy"></param>
        /// <returns>true: neu tan cong duoc
        /// false: neu khong tan cong duoc</returns>
        protected bool CanAttack(IEnemy enemy)
        {
            if ((Distance(this.m_pointPos, enemy.Position) <= this.m_nRange) && !enemy.IsDeath())
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public int Distance(Point pStart, Point pEnd)
        {
            int iDistance;
            iDistance = (int)Math.Sqrt((Math.Pow((pStart.X - pEnd.X), 2) + Math.Pow((pStart.Y - pEnd.Y), 2)));
            return iDistance;
        }

        //tinh nang dac biet cua tower
        abstract public void SpecialSkill(IEnemy creep);

        //nang cap tower
        abstract public int Upgrade();

        /// <summary>
        /// Ban tru khi can thiet
        /// </summary>
        /// <returns>return: so tien thu duoc khi ban tru</returns>
        public int Sell()
        {
            // Cac tru cao cap se chi ban 50%~70% so tien ban dau
            return this.m_nCost * this.m_nRadixCost;
        }

        /// <summary>
        /// xay dung tower
        /// </summary>
        /// <param name="map">ban do hien hanh</param>
        /// <param name="bmpBuff">anh can hien thi len</param>
        /// <param name="pos">vi tri xay dung</param>
        /// <param name="iCurrMoney">so tien hien tai cua nguoi choi</param>
        /// <returns>so tien can thiet de xay dung tower</returns>
        public int Build(IMap map, Bitmap bmpBuff, Point pos, int iCurrMoney)
        {
            // Truong hop build duoc
            if (CanBuild(map, pos, iCurrMoney))
            {
                // Gan thuoc tinh m_pointPos = pos
                m_pointPos = pos;

                // Ve tower, transparent
                this.DrawTower(bmpBuff, pos);

                // Tra ve so tien bi mat khi build
                return this.m_nCost;
            }

            return 0;
        }

        /// <summary>
        /// ham de ve tower tai vi tri pos can ve
        /// </summary>
        /// <param name="bmpBuff">bitmap can ve len</param>
        /// <param name="pos">vi tri can ve tower</param>
        public void DrawTower(Bitmap bmpBuff, Point pos)
        {
            //gan lai vi tri cho tower
            this.m_pointPos = pos;

            Graphics g = Graphics.FromImage(bmpBuff);

            //ve hinh ra hcn, lay pos la tam cua hcn
            g.DrawImage(this.m_bmDisplay, this.GetRect(pos), 0, 0, this.m_iWidth, this.m_iHeight, GraphicsUnit.Pixel, this.m_imgAtt);

            g.Dispose();
        }

        /// <summary>
        /// ham de ve tower tai mot vi tri co san
        /// </summary>
        /// <param name="bmpBuff">bitmap can ve len</param>
        /// <param name="bFillBground">
        /// true: neu muon to nen truoc khi ve
        /// false: neu khong muon to nen
        /// </param>
        /// <param name="color">mau nen muon fill ( chi su dung mau nay khi bFillBground = true</param>
        public void DrawTower(Bitmap bmpBuff, bool bFillBground, Color color)
        {
            Graphics g = Graphics.FromImage(bmpBuff);

            if (bFillBground)
            {
                Brush brush = new SolidBrush(color);
                g.FillRectangle(brush, this.GetRect());
                brush.Dispose();
            }

            g.DrawImage(this.m_bmDisplay, this.GetRect(), 0, 0, this.m_iWidth, this.m_iHeight, GraphicsUnit.Pixel, this.m_imgAtt);

            g.Dispose();
        }

        /// <summary>
        /// ham de ve tower tai vi tri pos
        /// </summary>
        /// <param name="bmpBuff">bitmap can ve len</param>
        /// <param name="bFillBground">co muon fill color hay khong
        /// true: muon fill color
        /// false: khong muon fill</param>
        /// <param name="color">mau muon fill ( dung khi bFillColor = true</param>
        /// <param name="pos">vi tri muon ve tower</param>
        public void DrawTower(Bitmap bmpBuff, bool bFillBground, Color color, Point pos)
        {
            //gan lai vi tri cho tower
            this.m_pointPos = pos;

            Graphics g = Graphics.FromImage(bmpBuff);

            if (bFillBground)
            {
                Brush brush = new SolidBrush(color);
                g.FillRectangle(brush, this.GetRect(pos));
                brush.Dispose();
            }

            g.DrawImage(this.m_bmDisplay, this.GetRect(pos), 0, 0, this.m_iWidth, this.m_iHeight, GraphicsUnit.Pixel, this.m_imgAtt);

            g.Dispose();
        }

        /// <summary>
        /// ham lay ve dien tich cua 1 tower tinh tu 1 diem bat ky
        /// </summary>
        /// <param name="pos">diem truyen vao de tinh dien tich, pos la tam cua hcn</param>
        /// <returns>dien tich cua tower chiem cho</returns>
        public Rectangle GetRect(Point pos)
        {
            return new Rectangle(pos.X - this.m_iWidth / 2, pos.Y - this.m_iHeight / 2, this.m_iWidth, this.m_iHeight);
        }

        /// <summary>
        /// ham lay ve dien tich cua 1 tower tinh tu vi tri tower do dang duoc xay dung
        /// </summary>
        /// <returns></returns>
        public Rectangle GetRect()
        {
            return new Rectangle(this.m_pointPos.X - this.m_iWidth / 2, this.m_pointPos.Y - this.m_iHeight / 2, this.m_iWidth, this.m_iHeight);
        }

        /// <summary>
        /// kiem tra xem tower cua build duoc tai vi tri p hay khong
        /// </summary>
        /// <param name="map">ban do hien tai cua vong choi</param>
        /// <param name="pos">vi tri can build</param>
        /// <param name="iCurrMoney">so tien hien tai cua nguoi choi</param>
        /// <returns>
        /// true: cho phep build
        /// false: khong cho phep build
        /// </returns>
        public bool CanBuild(IMap map, Point pos, int iCurrMoney)
        {
            // Xet cac dieu kien de build tower

            //kiem tra xem co du tien de mua tower hay khong
            if (this.m_nCost > iCurrMoney)
            {
                return false;
            }

            //kiem tra xem vi tri dat tower co trung voi vi tri dat tree hay khong
            if (map.IsInListPointOfTree(this.GetRect(pos)))
            {
                return false;
            }

            //kiem tra xem vi tri dat tower co trung voi nhung vi tri da dat tower truoc day hay khong
            if (map.IsInListTower(this.GetRect(pos)))
            {
                return false;
            }

            //neu thoa het cac dieu kien
            return true;
        }

        /// <summary>
        /// ham de tan cong creep
        /// </summary>
        /// <param name="enemy">quan linh dang bi tan cong</param>
        protected void Attack(ref IEnemy enemy)
        {            
            //cap nhat lai HP cua quan linh bi ban
            int damageReduce = (m_nDamage * enemy.Armor) / 100;
            enemy.HP = enemy.HP - m_nDamage + damageReduce;
            
            Thread.Sleep(m_nAtkSpeed);
        }

        #endregion
    }

    public class ArrowTowerL1 : ITower
    {
        public ArrowTowerL1()
        {
            m_sName = "Arrow Tower L1";
            m_nDamage = 11;
            m_nRange = 100;
            m_nAtkSpeed = 1000;
            m_nLevel = 1;
            m_nCost = 10;
            m_nRadixCost = 1;

            m_bmDisplay = Resources.SpecialTower1;
            m_iHeight = this.m_bmDisplay.Height;
            m_iWidth = this.m_bmDisplay.Width;

            m_imgAtt = new ImageAttributes();
            Color c = new Color();
            c = this.m_bmDisplay.GetPixel(0, 0);
            m_imgAtt.SetColorKey(c, c);

            this.m_AttackEnemy = null;
            this.m_IsDestroy = false;
        }

        public override int Upgrade()
        {
            ArrowTowerL2 ar2 = new ArrowTowerL2();
            // Huy ArrowTowerL1 di
            // Build ArrowTowerL2
            //ar2.Build(m_pointPos);

            return ar2.Cost;
        }


        public override void SpecialSkill(IEnemy creep)
        {
            // Khong co special skill
            return;
        }
    }

    public class ArrowTowerL2 : ITower
    {
        public ArrowTowerL2()
        {
            m_sName = "Arrow Tower L2";
            m_nDamage = 26;
            m_nRange = 100;
            m_nAtkSpeed = 1000;         //1000 la min, dung co cho lon qua :|
            m_nLevel = 2;
            m_nCost = 15;
            m_nRadixCost = 1;

            m_bmDisplay = Resources.SpecialTower2;

            m_iHeight = this.m_bmDisplay.Height;
            m_iWidth = this.m_bmDisplay.Width;

            m_imgAtt = new ImageAttributes();
            Color c = new Color();
            c = this.m_bmDisplay.GetPixel(0, 0);
            m_imgAtt.SetColorKey(c, c);

            this.m_AttackEnemy = null;
            this.m_IsDestroy = false;
        }

        public override int Upgrade()
        {
            return 0;
        }

        public override void SpecialSkill(IEnemy creep)
        {
            // Khong co special skill
            return;
        }
    }

    public class ArrowTowerL3 : ITower
    {
        public ArrowTowerL3()
        {
            //may sua may cai nay di
            m_sName = "Arrow Tower L3";
            m_nDamage = 26;
            m_nRange = 100;             //
            m_nAtkSpeed = 1000;
            m_nLevel = 2;
            m_nCost = 15;
            m_nRadixCost = 1;

            m_bmDisplay = Resources.NormalTower1_level1;

            m_iHeight = this.m_bmDisplay.Height;
            m_iWidth = this.m_bmDisplay.Width;

            m_imgAtt = new ImageAttributes();
            Color c = new Color();
            c = this.m_bmDisplay.GetPixel(0, 0);
            m_imgAtt.SetColorKey(c, c);

            this.m_AttackEnemy = null;
            this.m_IsDestroy = false;
                        
        }
        public override int Upgrade()
        {
            throw new Exception("The method or operation is not implemented.");
        }
        public override void SpecialSkill(IEnemy creep)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}
